﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using Rung.Net.Events;
using Rung.Net.Enums;
using Rung.Net.Base;
using Rung.Net.Simple;
using Rung.Net.Cache;
using Rung.Net.Session;
using Rung.Net.Test.Utilities;
using System.Drawing.Drawing2D;

namespace Rung.Net.Test
{
    public partial class SimpleMainFormS : Form
    {
        INetBaseServer<byte[]> server;
        // 刷新客户端列表
        System.Timers.Timer timer;
        private object OBJ_Clients = new object();
        private bool simulateLoginCheck = false;// 模拟登陆验证
        private bool simulateConnectCheck = false;// 模拟连接验证

        public SimpleMainFormS()
        {
            InitializeComponent();
        }

        private void MainFormS_Load(object sender, EventArgs e)
        {
            this.timer = new System.Timers.Timer(500);
            this.timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);

            ddlNetModuleType.SelectedIndex = 0;
            ddlAddresses.DataSource = NetUtility.GetLocalIpV4();

            ddlNetModuleType.SelectedIndex = 1;
            btnStart_Click(this, null);
        }

        private void MainFormS_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (timer != null)
            {
                timer.Stop();
                timer.Dispose();
            }
            server.Dispose();

            // 关闭所有客户端
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (lbClient.IsDisposed == false && timer.Enabled && lbClient.IsHandleCreated)
            {
                lbClient.Invoke(new Action(() =>
                {
                    if (lbClient.IsDisposed == false && timer.Enabled && lbClient.IsHandleCreated)
                    {
                        object selectedItem = lbClient.SelectedItem;
                        lbClient.Items.Clear();

                        lock (OBJ_Clients)
                        {
                            foreach (var c in server.Clients)
                            {
                                lbClient.Items.Add(c.Value);
                            }
                        }

                        lbClient.SelectedItem = selectedItem;
                    }
                }));
            }
        }

        #region 下拉框切换网络模式
        private void ddlNetModuleType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.server != null)
            {
                this.server.Dispose();
            }

            switch (ddlNetModuleType.SelectedIndex)
            {
                case 0:
                    this.server = new SimpleServer();
                    tabOperation.Selecting += disableCacheEvent;
                    tabOperation.Selecting += disableSessionEvent;
                    break;
                case 1:
                    this.server = new CacheServer();
                    tabOperation.Selecting -= disableCacheEvent;
                    tabOperation.Selecting -= disableSessionEvent;
                    tabOperation.Selecting += disableSessionEvent;
                    break;
                case 2:
                    this.server = new SessionServer();
                    tabOperation.Selecting -= disableCacheEvent;
                    tabOperation.Selecting -= disableSessionEvent;
                    tabOperation.Selecting += disableCacheEvent;
                    break;
                default:
                    MessageBox.Show("未知模式。");
                    break;
            }
        }
        private TabControlCancelEventHandler disableCacheEvent = new TabControlCancelEventHandler((s, args) => { if (args.TabPageIndex == 1)args.Cancel = true; });
        private TabControlCancelEventHandler disableSessionEvent = new TabControlCancelEventHandler((s, args) => { if (args.TabPageIndex == 2)args.Cancel = true; });
        #endregion

        // 【开启服务】
        private void btnStart_Click(object sender, EventArgs e)
        {
            if (!server.IsOnline)
            {
                //Set the deefault echo mode for everything that is received by the server.
                //server.EchoMode = NetEchoMode.EchoAll;

                if (server is CacheServer)
                {
                    (server as CacheServer).NeedFeedbackPackageReceived = true;
                }

                if (server is Session.SessionServer)
                {
                    (server as Session.SessionServer).TimeoutSecond = 5;
                    (server as Session.SessionServer).OnSessionEnd += new SessionEndEventHandler(SimpleMainFormS_OnSessionEnd);
                }

                //Attach event handlers
                server.OnClientAccepted += new NetClientAcceptedEventHandler(server_OnClientAccepted);
                server.OnClientConnected += new NetClientConnectedEventHandler(server_OnClientConnected);
                server.OnClientDisconnected += new NetClientDisconnectedEventHandler(server_OnClientDisconnected);
                server.OnClientRejected += new NetClientRejectedEventHandler(server_OnClientRejected);
                server.OnReceived += new NetClientReceivedEventHandler<byte[]>(server_OnReceived);
                server.OnStarted += new NetStartedEventHandler(server_OnStarted);
                server.OnStopped += new NetStoppedEventHandler(server_OnStopped);

                string port = System.Configuration.ConfigurationManager.AppSettings["Cache_ServerPort"];
                server.Start((IPAddress)ddlAddresses.SelectedItem, int.Parse(port));

                timer.Start();
            }
        }

        // 【发送消息】
        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            string msg = txbTextMsg.Text.Trim();
            if (string.IsNullOrEmpty(msg)) return;

            ClientItem<byte[]> c = lbClient.SelectedItem as ClientItem<byte[]>;
            if (c != null)
            {
                string data = NetUtility.GetFullMessage(MessageType.EchoAllClient, msg);
                server.DispatchTo(c.Id, NetUtility.C(data));
            }
        }

        // 【广播消息】
        private void btnEchoMsg_Click(object sender, EventArgs e)
        {
            string data = NetUtility.GetFullMessage(MessageType.EchoAllClient, "服务器广播！都他妈给我听好了！");
            server.DispatchAll(NetUtility.C(data));
        }

        // 【清空信息】
        private void btnClearInfo_Click(object sender, EventArgs e)
        {
            lbInfo.Items.Clear();
        }

        private void lbInfo_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0) return;

            Color c = Color.Black;
            if (null != lbInfo.Items[e.Index])
            {
                if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                {
                    c = Color.White;
                    e.Graphics.FillRectangle(new SolidBrush(SystemColors.GradientActiveCaption), e.Bounds);
                    e.DrawFocusRectangle();
                }
                else
                {
                    e.Graphics.FillRectangle(Brushes.White, e.Bounds);
                }

                string item = lbInfo.Items[e.Index].ToString();
                if (!string.IsNullOrEmpty(item))
                {
                    int index = item.IndexOf('/');
                    if (index > 0)
                    {
                        if (c != Color.White) c = Color.FromArgb(int.Parse(item.Substring(0, index)));
                        e.Graphics.DrawString(item.Substring(index + 1), e.Font, new SolidBrush(c), e.Bounds);
                    }
                }
            }
        }

        private void lbInfo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (null != lbInfo.SelectedItem)
                txbInfo.Text = lbInfo.SelectedItem.ToString();
        }

        void server_OnStopped(object sender, NetStoppedEventArgs e)
        {
            write("【停】\t\t\tOnStopped", Color.Gray);
        }
        void server_OnStarted(object sender, NetStartedEventArgs e)
        {
            write("【启】\t\t\tOnStarted", Color.Gray);
        }
        void server_OnReceived(object sender, NetClientReceivedEventArgs<byte[]> e)
        {
            write("【收】" + NetUtility.C(e.Data) + "\t\t\tOnReceived", Color.Blue);

            byte[] data;
            string receive = NetUtility.C(e.Data);
            int messageType = NetUtility.GetMessageType(receive);
            string body = NetUtility.GetMessageBody(receive);
            switch (messageType)
            {
                case MessageType.Login:
                    #region 登陆
                    lock (OBJ_Clients)
                    {
                        var client = server.Clients[e.Guid];
                        if (client != null) client.Name = body;

                        /* 模拟一些登陆验证操作 */
                        if (simulateLoginCheck && client.Id.ToByteArray()[0] < 120)
                        {
                            client.Stop();
                            write("模拟登陆验证失败。" + NetUtility.C(e.Data), Color.LawnGreen);
                            e.EchoMode = NetEchoMode.None;
                        }
                        else
                        {
                            //write("模拟登陆验证成功。", Color.Green);

                            e.EchoMode = NetEchoMode.None;

                            #region 通知其他用户：该用户上线
                            lock (OBJ_Clients)
                            {
                                body = string.Format("{0}{1}{2}", e.Guid.ToString(), LevelSeperators.Level1, this.server.Clients[e.Guid].Name);
                            }
                            data = NetUtility.C(NetUtility.GetFullMessage(MessageType.Login, body));
                            this.server.DispatchAllExcept(e.Guid, data);
                            #endregion

                            #region 向该用户推送：在线用户列表
                            List<string> clients = new List<string>();
                            lock (OBJ_Clients)
                            {
                                foreach (var c in this.server.Clients)
                                {
                                    clients.Add(string.Format("{0}{1}{2}", c.Value.Id, LevelSeperators.Level2, c.Value.Name));
                                }
                            }
                            body = string.Format(string.Join(LevelSeperators.Level1.ToString(), clients.ToArray()));
                            data = NetUtility.C(NetUtility.GetFullMessage(MessageType.GetAllOnlineClient, body));
                            try
                            {
                                this.server.DispatchTo(client.Id, data);
                            }
                            catch (Exception ex)
                            {
                                write("【收】" + ex.Message + "\t\t\tOnReceived", Color.Red);
                            }
                            #endregion
                        }
                    }
                    #endregion
                    break;
                case MessageType.TalkToServer:
                    #region 客户端与服务端的对话
                    e.EchoMode = NetEchoMode.None;
                    server.DispatchTo(e.Guid, NetUtility.C(NetUtility.C(e.Data) + "你妹啊！"));
                    #endregion
                    break;
                case MessageType.TalkToClient:
                    #region 客户端与其他客户端的对话
                    e.EchoMode = NetEchoMode.None;
                    string[] ids_message = body.Split(LevelSeperators.Level1);
                    string[] ids = ids_message[0].Split(LevelSeperators.Level2);
                    string message = ids_message[1];
                    foreach (var id in ids)
                    {
                        body = string.Format("{0}{1}{2}", e.Guid, LevelSeperators.Level1, message);
                        server.DispatchTo(Guid.Parse(id), NetUtility.C(NetUtility.GetFullMessage(MessageType.TalkToClient, body)));
                    }
                    #endregion
                    break;
                case MessageType.CacheFinished:
                    #region 文件传输完成
                    string[] bodys = body.Split(LevelSeperators.Level1);
                    string fileLength = bodys[0];
                    string oriFileName = bodys[1];
                    string desFileName = bodys[2];
                    try
                    {
                        List<Rung.Net.Test.Utilities.DataProvider.TestSerializableClass> testClassList =
                                    Rung.Common.SerializeHelper.DeSerialize<List<Rung.Net.Test.Utilities.DataProvider.TestSerializableClass>>(desFileName);
                        //foreach (var c in testClassList)
                        //{
                        //    write(string.Format("{0}\t{1}\t{2}", c.I, c.Date.ToShortDateString(), c.S.Length), Color.BurlyWood);
                        //}
                        write(string.Format("文件长度：{0}字节，序列化元素个数：{1}个", fileLength, testClassList.Count), Color.BurlyWood);
                    }
                    catch
                    {
                        write("【传输完成】（OnReceived.CacheFinished 消息）", Color.Coral);
                        write(string.Format("原文件名：{0}", oriFileName), Color.Blue);
                        write(string.Format("本地文件：{0}", desFileName), Color.Blue);
                        write(string.Format("长度：{0}", fileLength), Color.Blue);

                        System.IO.FileInfo fi = new System.IO.FileInfo(desFileName);
                        System.IO.File.Move(desFileName, 
                            string.Format("【我日】{0}-{1}-{2}_{3}", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, oriFileName));
                    }
                    #endregion
                    break;
                case MessageType.EchoAllClientExceptSender:
                    e.EchoMode = NetEchoMode.EchoAllExceptSender;
                    server.DispatchTo(e.Guid, NetUtility.C("EchoAllClient：" + NetUtility.C(e.Data)));
                    break;
                case MessageType.EchoAllClient:
                    e.EchoMode = NetEchoMode.EchoAll;
                    server.DispatchTo(e.Guid, NetUtility.C("EchoAllClient：" + NetUtility.C(e.Data)));
                    break;
                case MessageType.EchoSender:
                    e.EchoMode = NetEchoMode.None;
                    server.DispatchTo(e.Guid, NetUtility.C("EchoSender：" + NetUtility.C(e.Data)));
                    break;
                case MessageType.EchoAll:
                default:
                    break;
            }
        }
        void server_OnClientDisconnected(object sender, NetClientDisconnectedEventArgs e)
        {
            write("【断】\t\t\tOnClientDisconnected", Color.Gray);

            string body;
            byte[] data;

            #region 通知其他用户该用户下线
            lock (OBJ_Clients)
            {
                body = e.Guid.ToString();
            }
            data = NetUtility.C(NetUtility.GetFullMessage(MessageType.Logout, body));
            this.server.DispatchAllExcept(e.Guid, data);
            #endregion
        }
        void server_OnClientConnected(object sender, NetClientConnectedEventArgs e)
        {
            /*The client can be rejected manually*/
            //e.Reject = true;

            if (simulateConnectCheck && e.Guid.ToByteArray()[0] < 60)
            {
                e.Reject = true;
                write("【连】：GUID 不爽，拒绝。\t\t\tOnClientConnected", Color.Gray);
            }
            else
                write("【连】：通过。\t\t\t", Color.Gray);
        }
        void server_OnClientAccepted(object sender, NetClientAcceptedEventArgs e)
        {
            write("【接受】\t\t\tOnClientAccepted", Color.Gray);
        }
        void server_OnClientRejected(object sender, NetClientRejectedEventArgs e)
        {
            write("【拒绝】\t\t\tOnClientRejected", Color.Gray);
        }
        void SimpleMainFormS_OnSessionEnd(object sender, SessionEndEventArgs e)
        {
            write("【会话结束】", Color.Gray);

            #region 通知其他用户该用户下线
            byte[] data;
            lock (OBJ_Clients)
            {
                data = NetUtility.C(NetUtility.GetFullMessage(MessageType.Logout, e.Guid.ToString()));
            }
            this.server.DispatchAllExcept(e.Guid, data);
            #endregion
        }

        void write(string s, Color c)
        {
            if (!lbInfo.IsDisposed)
            {
                Invoke(new Action(delegate
                {
                    int selectedIndex = lbInfo.SelectedIndex;
                    lbInfo.Items.Add(string.Format("{0}/{1}", c.ToArgb(), s));
                    lbInfo.SelectedIndex = lbInfo.Items.Count - 1;

                    if (lbInfo.TopIndex <= selectedIndex) lbInfo.SelectedIndex = selectedIndex;
                }));
            }
        }
    }
}
